From: kaf24@firebug.cl.cam.ac.uk Date: Tue, 10 Jan 2006 17:25:45 +0000 (+0100) Subject: Add new map_domain_page_global() interface to allow mappings X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~16541^2~70 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=af58611df658bf42f7d9bb2ff8373dfba3a778ee;p=xen.git Add new map_domain_page_global() interface to allow mappings that are accessible in all contexts and address spaces. Used by shadow code and vmx code. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 0915873283..e6c59eb58d 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -2150,8 +2150,8 @@ static void shadow_update_pagetables(struct vcpu *v) if ( max_mode & (SHM_enable | SHM_external) ) { if ( likely(v->arch.guest_vtable != NULL) ) - unmap_domain_page(v->arch.guest_vtable); - v->arch.guest_vtable = map_domain_page(gmfn); + unmap_domain_page_global(v->arch.guest_vtable); + v->arch.guest_vtable = map_domain_page_global(gmfn); } /* @@ -2187,8 +2187,8 @@ static void shadow_update_pagetables(struct vcpu *v) ) { if ( v->arch.shadow_vtable ) - unmap_domain_page(v->arch.shadow_vtable); - v->arch.shadow_vtable = map_domain_page(smfn); + unmap_domain_page_global(v->arch.shadow_vtable); + v->arch.shadow_vtable = map_domain_page_global(smfn); } #if CONFIG_PAGING_LEVELS == 2 @@ -2204,8 +2204,8 @@ static void shadow_update_pagetables(struct vcpu *v) if ( unlikely(!(hl2mfn = __shadow_status(d, gpfn, PGT_hl2_shadow))) ) hl2mfn = shadow_hl2_table(d, gpfn, gmfn, smfn); if ( v->arch.hl2_vtable ) - unmap_domain_page(v->arch.hl2_vtable); - v->arch.hl2_vtable = map_domain_page(hl2mfn); + unmap_domain_page_global(v->arch.hl2_vtable); + v->arch.hl2_vtable = map_domain_page_global(hl2mfn); } /* diff --git a/xen/arch/x86/shadow32.c b/xen/arch/x86/shadow32.c index a8d7abbf11..b70db99eb4 100644 --- a/xen/arch/x86/shadow32.c +++ b/xen/arch/x86/shadow32.c @@ -733,7 +733,7 @@ static void alloc_monitor_pagetable(struct vcpu *v) ASSERT(mmfn_info != NULL); mmfn = page_to_pfn(mmfn_info); - mpl2e = (l2_pgentry_t *)map_domain_page(mmfn); + mpl2e = (l2_pgentry_t *)map_domain_page_global(mmfn); memset(mpl2e, 0, PAGE_SIZE); memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE], @@ -794,7 +794,7 @@ void free_monitor_pagetable(struct vcpu *v) * Then free monitor_table. */ mfn = pagetable_get_pfn(v->arch.monitor_table); - unmap_domain_page(v->arch.monitor_vtable); + unmap_domain_page_global(v->arch.monitor_vtable); free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); @@ -929,7 +929,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.guest_vtable && (v->arch.guest_vtable != __linear_l2_table) ) { - unmap_domain_page(v->arch.guest_vtable); + unmap_domain_page_global(v->arch.guest_vtable); } if ( (mode & (SHM_translate | SHM_external)) == SHM_translate ) v->arch.guest_vtable = __linear_l2_table; @@ -942,7 +942,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.shadow_vtable && (v->arch.shadow_vtable != __shadow_linear_l2_table) ) { - unmap_domain_page(v->arch.shadow_vtable); + unmap_domain_page_global(v->arch.shadow_vtable); } if ( !(mode & SHM_external) ) v->arch.shadow_vtable = __shadow_linear_l2_table; @@ -955,7 +955,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.hl2_vtable && (v->arch.hl2_vtable != __linear_hl2_table) ) { - unmap_domain_page(v->arch.hl2_vtable); + unmap_domain_page_global(v->arch.hl2_vtable); } if ( (mode & (SHM_translate | SHM_external)) == SHM_translate ) v->arch.hl2_vtable = __linear_hl2_table; @@ -2906,8 +2906,8 @@ void __update_pagetables(struct vcpu *v) if ( max_mode & (SHM_enable | SHM_external) ) { if ( likely(v->arch.guest_vtable != NULL) ) - unmap_domain_page(v->arch.guest_vtable); - v->arch.guest_vtable = map_domain_page(gmfn); + unmap_domain_page_global(v->arch.guest_vtable); + v->arch.guest_vtable = map_domain_page_global(gmfn); } /* @@ -2932,8 +2932,8 @@ void __update_pagetables(struct vcpu *v) if ( max_mode == SHM_external ) { if ( v->arch.shadow_vtable ) - unmap_domain_page(v->arch.shadow_vtable); - v->arch.shadow_vtable = map_domain_page(smfn); + unmap_domain_page_global(v->arch.shadow_vtable); + v->arch.shadow_vtable = map_domain_page_global(smfn); } /* @@ -2948,8 +2948,8 @@ void __update_pagetables(struct vcpu *v) if ( unlikely(!(hl2mfn = __shadow_status(d, gpfn, PGT_hl2_shadow))) ) hl2mfn = shadow_hl2_table(d, gpfn, gmfn, smfn); if ( v->arch.hl2_vtable ) - unmap_domain_page(v->arch.hl2_vtable); - v->arch.hl2_vtable = map_domain_page(hl2mfn); + unmap_domain_page_global(v->arch.hl2_vtable); + v->arch.hl2_vtable = map_domain_page_global(hl2mfn); } /* diff --git a/xen/arch/x86/shadow_public.c b/xen/arch/x86/shadow_public.c index 931a31f83f..55d0196e47 100644 --- a/xen/arch/x86/shadow_public.c +++ b/xen/arch/x86/shadow_public.c @@ -151,6 +151,8 @@ free_shadow_fl1_table(struct domain *d, unsigned long smfn) for (i = 0; i < L1_PAGETABLE_ENTRIES; i++) put_page_from_l1e(pl1e[i], d); + + unmap_domain_page(pl1e); } /* @@ -254,6 +256,7 @@ static pagetable_t page_table_convert(struct domain *d) pae_l3 = map_domain_page(pagetable_get_pfn(d->arch.phys_table)); for (i = 0; i < PDP_ENTRIES; i++) l3[i] = l3e_from_pfn(l3e_get_pfn(pae_l3[i]), __PAGE_HYPERVISOR); + unmap_domain_page(pae_l3); unmap_domain_page(l4); unmap_domain_page(l3); @@ -275,7 +278,7 @@ static void alloc_monitor_pagetable(struct vcpu *v) ASSERT( mmfn_info ); mmfn = page_to_pfn(mmfn_info); - mpl4e = (l4_pgentry_t *) map_domain_page(mmfn); + mpl4e = (l4_pgentry_t *) map_domain_page_global(mmfn); memcpy(mpl4e, &idle_pg_table[0], PAGE_SIZE); mpl4e[l4_table_offset(PERDOMAIN_VIRT_START)] = l4e_from_paddr(__pa(d->arch.mm_perdomain_l3), __PAGE_HYPERVISOR); @@ -298,7 +301,7 @@ void free_monitor_pagetable(struct vcpu *v) * free monitor_table. */ mfn = pagetable_get_pfn(v->arch.monitor_table); - unmap_domain_page(v->arch.monitor_vtable); + unmap_domain_page_global(v->arch.monitor_vtable); free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); @@ -332,7 +335,7 @@ static void alloc_monitor_pagetable(struct vcpu *v) ASSERT(mmfn_info != NULL); mmfn = page_to_pfn(mmfn_info); - mpl2e = (l2_pgentry_t *)map_domain_page(mmfn); + mpl2e = (l2_pgentry_t *)map_domain_page_global(mmfn); memset(mpl2e, 0, PAGE_SIZE); memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE], @@ -393,7 +396,7 @@ void free_monitor_pagetable(struct vcpu *v) * Then free monitor_table. */ mfn = pagetable_get_pfn(v->arch.monitor_table); - unmap_domain_page(v->arch.monitor_vtable); + unmap_domain_page_global(v->arch.monitor_vtable); free_domheap_page(pfn_to_page(mfn)); v->arch.monitor_table = mk_pagetable(0); @@ -977,7 +980,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.guest_vtable && (v->arch.guest_vtable != __linear_l2_table) ) { - unmap_domain_page(v->arch.guest_vtable); + unmap_domain_page_global(v->arch.guest_vtable); } if ( (mode & (SHM_translate | SHM_external)) == SHM_translate ) v->arch.guest_vtable = __linear_l2_table; @@ -990,7 +993,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.shadow_vtable && (v->arch.shadow_vtable != __shadow_linear_l2_table) ) { - unmap_domain_page(v->arch.shadow_vtable); + unmap_domain_page_global(v->arch.shadow_vtable); } if ( !(mode & SHM_external) && d->arch.ops->guest_paging_levels == 2) v->arch.shadow_vtable = __shadow_linear_l2_table; @@ -1004,7 +1007,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) if ( v->arch.hl2_vtable && (v->arch.hl2_vtable != __linear_hl2_table) ) { - unmap_domain_page(v->arch.hl2_vtable); + unmap_domain_page_global(v->arch.hl2_vtable); } if ( (mode & (SHM_translate | SHM_external)) == SHM_translate ) v->arch.hl2_vtable = __linear_hl2_table; diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index e6dfd5f13e..2dd4925947 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -98,7 +98,8 @@ void vmx_relinquish_resources(struct vcpu *v) /* unmap IO shared page */ struct domain *d = v->domain; if ( d->arch.vmx_platform.shared_page_va ) - unmap_domain_page((void *)d->arch.vmx_platform.shared_page_va); + unmap_domain_page_global( + (void *)d->arch.vmx_platform.shared_page_va); } destroy_vmcs(&v->arch.arch_vmx); diff --git a/xen/arch/x86/vmx_vmcs.c b/xen/arch/x86/vmx_vmcs.c index 80ec8f201f..f10124f99d 100644 --- a/xen/arch/x86/vmx_vmcs.c +++ b/xen/arch/x86/vmx_vmcs.c @@ -193,7 +193,7 @@ static void vmx_map_io_shared_page(struct domain *d) domain_crash_synchronous(); } - p = map_domain_page(mpfn); + p = map_domain_page_global(mpfn); if (p == NULL) { printk("Can not map io request shared page for VMX domain.\n"); domain_crash_synchronous(); diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c index 38d822a0f5..8b28103cf8 100644 --- a/xen/arch/x86/x86_32/domain_page.c +++ b/xen/arch/x86/x86_32/domain_page.c @@ -101,3 +101,71 @@ void unmap_domain_pages(void *va, unsigned int order) for ( i = 0; i < (1U << order); i++ ) l1e_add_flags(cache->l1tab[idx+i], READY_FOR_TLB_FLUSH); } + +#define GLOBALMAP_BITS (IOREMAP_MBYTES << (20 - PAGE_SHIFT)) +static unsigned long inuse[BITS_TO_LONGS(GLOBALMAP_BITS)]; +static unsigned long garbage[BITS_TO_LONGS(GLOBALMAP_BITS)]; +static unsigned int inuse_cursor; +static spinlock_t globalmap_lock = SPIN_LOCK_UNLOCKED; + +void *map_domain_page_global(unsigned long pfn) +{ + l2_pgentry_t *pl2e; + l1_pgentry_t *pl1e; + unsigned int idx, i; + unsigned long va; + + ASSERT(!in_irq() && local_irq_is_enabled()); + + spin_lock(&globalmap_lock); + + for ( ; ; ) + { + idx = find_next_zero_bit(inuse, GLOBALMAP_BITS, inuse_cursor); + va = IOREMAP_VIRT_START + (idx << PAGE_SHIFT); + + /* End of round? If not then we're done in this loop. */ + if ( va < FIXADDR_START ) + break; + + /* /First/, clean the garbage map and update the inuse list. */ + for ( i = 0; i < ARRAY_SIZE(garbage); i++ ) + { + unsigned long x = xchg(&garbage[i], 0); + inuse[i] &= ~x; + } + + /* /Second/, flush all TLBs to get rid of stale garbage mappings. */ + flush_tlb_all(); + + inuse_cursor = 0; + } + + set_bit(idx, inuse); + inuse_cursor = idx + 1; + + spin_unlock(&globalmap_lock); + + pl2e = virt_to_xen_l2e(va); + pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(va); + *pl1e = l1e_from_pfn(pfn, __PAGE_HYPERVISOR); + + return (void *)va; +} + +void unmap_domain_page_global(void *va) +{ + unsigned long __va = (unsigned long)va; + l2_pgentry_t *pl2e; + l1_pgentry_t *pl1e; + unsigned int idx; + + /* /First/, we zap the PTE. */ + pl2e = virt_to_xen_l2e(__va); + pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va); + *pl1e = l1e_empty(); + + /* /Second/, we add to the garbage map. */ + idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT; + set_bit(idx, garbage); +} diff --git a/xen/include/xen/domain_page.h b/xen/include/xen/domain_page.h index ce152aece2..8e0a524a42 100644 --- a/xen/include/xen/domain_page.h +++ b/xen/include/xen/domain_page.h @@ -17,16 +17,26 @@ /* * Maps a given range of page frames, returning the mapped virtual address. The - * pages are now accessible until a corresponding call to unmap_domain_page(). + * pages are now accessible within the current domain until a corresponding + * call to unmap_domain_page(). */ extern void *map_domain_pages(unsigned long pfn, unsigned int order); /* - * Pass a VA within the first page of a range previously mapped with - * map_omain_pages(). Those pages will then be removed from the mapping lists. + * Pass a VA within the first page of a range previously mapped in the context + * of the currently-executing domain via a call to map_domain_pages(). Those + * pages will then be removed from the mapping lists. */ extern void unmap_domain_pages(void *va, unsigned int order); +/* + * Similar to the above calls, except the mapping is accessible in all + * address spaces (not just within the domain that created the mapping). Global + * mappings can also be unmapped from any context. + */ +extern void *map_domain_page_global(unsigned long pfn); +extern void unmap_domain_page_global(void *va); + #define DMCACHE_ENTRY_VALID 1U #define DMCACHE_ENTRY_HELD 2U @@ -90,6 +100,9 @@ domain_mmap_cache_destroy(struct domain_mmap_cache *cache) #define map_domain_pages(pfn,order) phys_to_virt((pfn)<